/**
 * @brief Test C++ code for IPC
 * C++ file used in client code
 * //Cpp下实现一个简单的udp服务端的基本流程
 * 1. 创建socket
 * 2. 绑定端口
 * 3. 等待接收消息
 * 4. 接收消息并打印
 * 5. 关闭socket
 * 6. 退出程序
 *
 * 编译方法：g++ -o server testcpp.cpp
 *
 */
// 思路：创建一个socket 向对手端口发送消息。采用udp协议，不保证可靠性。
//  需要掌握socket编程的基本知识即可。
// 其次是需要掌握Cpp面向对象的编程思路 重点是对类的封装以及使用习惯。
// 构造函数中创建一个socket
// 在成员方法中提供一个接口 绑定socket
// 在成员函数中提供一个接口 等待接收消息
// 在成员函数中提供一个接口 接收消息并打印
// 在成员函数中提供一个接口 关闭socket
// 在成员函数中提供一个接口 退出程序
// 创建socket
#include <iostream>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <vector>
#include "public.h"
class UdpServer
{
public:
    UdpServer(std::string ip);
    ~UdpServer();

        void UdpServerRecv();
        void UdpServerSend();
        void UdpCloseSocket();
        void UdpExit();
    public:
        int sockfd_send;

        struct sockaddr_in serv_addr_send;

        std::vector<char> recv_buf;
        std::vector<char> send_buf;
};

UdpServer::UdpServer(std::string ip)
{

    //服务端的发送代码
    if (-1 == (sockfd_send = socket(AF_INET, SOCK_DGRAM, 0)))
    {
        throw std::runtime_error("create sockfd_send error");
    }

    serv_addr_send.sin_family = AF_INET;
    serv_addr_send.sin_port = htons(SERVER_SEND_PORT);
    serv_addr_send.sin_addr.s_addr = inet_addr(ip.c_str());
}

UdpServer::~UdpServer()
{
    close(sockfd_listen);
    close(sockfd_send);
}

void UdpServer::UdpServerRecv()
{   
    int sockfd_listen;
    if (-1 == (sockfd_listen = socket(AF_INET, SOCK_DGRAM, 0)))
    {
        std::cerr << "socket error at line " << __LINE__ << ": " << strerror(errno) << std::endl;
        throw std::runtime_error("create sockfd_listen error");
    }

    struct sockaddr_in serv_addr_listen;
    serv_addr_listen.sin_family = AF_INET;
    serv_addr_listen.sin_port = htons(SERVER_LISTEN_PORT);
    serv_addr_listen.sin_addr.s_addr = inet_addr("127.0.0.1");

    // if(-1 == bind(sockfd,(const struct sockaddr *)&serv_addr,sizeof(serv_addr)))//C风格
    if (-1 == bind(sockfd_listen, reinterpret_cast<const struct sockaddr *>(&serv_addr_listen), sizeof(serv_addr_listen))) // 核心就是reinterpret_cast<p1's type*>(&p2) 我忘记写后面的()了
    {
        std::cout << "bind socket error" << std::endl;
        close(sockfd_listen);
        throw std::runtime_error("bind socket error");
    }

    socklen_t serv_addr_len = sizeof(sockfd_listen);
    ssize_t ret = recvfrom(sockfd_listen,recv_buf.data(),recv_buf.size(),0,reinterpret_cast<sockaddr *>(&sockfd_listen),&serv_addr_len);
    if(ret == -1)
    {
        std::cerr << "recvfrom error: " << __LINE__ << ": " << strerror(errno) << std::endl;
       throw std::runtime_error("recvfrom error");

    }
    //收到数据 目前只通过打印使用

}

void UdpServer::UdpServerSend()
{
    std::string ackstr = "ack";
    // std::string senddata = ackstr+recv_buf.data();
    // std::copy(senddata.begin(),senddata.end(),send_buf.begin());
    // send_buf.push_back('\0');
    //const char* cstr = send_buf.data();//提供C风格的字符串
    ssize_t ret = sendto(sockfd_send,ackstr.c_str(),ackstr.size(),0,reinterpret_cast<const sockaddr *>(&serv_addr_send),sizeof(serv_addr_send));
    if(ret == -1)
    {
        std::cerr << "sendto error: " << __LINE__ << ": " << strerror(errno) << std::endl;
        throw std::runtime_error("sendto error");
    }
    //发送成功 结束
}

int main(void)
{
    try
    {
        UdpServer server("127.0.0.1");
        std::cout<<"Start Server Test ==> Wait Data..."<<std::endl;
        while (1)
        {
            server.UdpServerRecv();
            std::cout<<"Recv Data:"<<server.recv_buf.data()<<std::endl;
            server.UdpServerSend();
            std::cout<<"Send Data Success"<<std::endl;
        
        }
    }
    catch(const std::exception& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
